package com.qf.service.impl;

import com.qf.entity.*;
import com.qf.feign.CityFeign;
import com.qf.feign.HotalFeign;
import com.qf.service.ISearchService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.IndexOperations;
import org.springframework.data.elasticsearch.core.document.Document;
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
import org.springframework.data.elasticsearch.core.query.UpdateQuery;
import org.springframework.data.elasticsearch.core.query.UpdateResponse;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class SearchServiceImpl implements ISearchService {

    @Autowired
    private ElasticsearchRestTemplate restTemplate;

    @Autowired
    private HotalFeign hotalFeign;

    @Autowired
    private CityFeign cityFeign;

    @Override
    public boolean createIndex() {

        IndexOperations operations = restTemplate.indexOps(Hotal.class);

        //判断是否存在
        if (!operations.exists()) {
            //不存在，则创建
            operations.create();

            //构建映射关系
            Document mapping = operations.createMapping();
            operations.putMapping(mapping);

            //同步数据库
            syncDatabase();

            return true;
        }

        return false;
    }

    @Override
    public boolean deleteIndex() {
        IndexOperations operations = restTemplate.indexOps(Hotal.class);
        return operations.exists() ? operations.delete() : false;
    }

    @Override
    public void syncDatabase() {
        //调用酒店服务获得酒店列表
        R<List<Hotal>> hotals = hotalFeign.list();
        //遍历保存到ES中
        hotals.getData().stream().forEach(hotal -> {
            //查询城市信息，设置到实体类中
            R<City> cityR = cityFeign.queryCity(hotal.getCid());
            hotal.setCity(cityR.getData());

            restTemplate.save(hotal);
        });
    }

    @Override
    public int insertHotal(Hotal hotal) {
        //获取酒店对应的城市信息
        R<City> cityR = cityFeign.queryCity(hotal.getCid());
        hotal.setCity(cityR.getData());

        restTemplate.save(hotal);
        return 1;
    }

    /**
     * 同步酒店的客房类型信息到ES
     *
     * ES - Painless 脚本
     *
     * @param room
     * @return
     */
    @Override
    public boolean insertRoom(Room room) {

        /**
         * 构建一个参数类型
         */
        Map<String, Object> roomMap = new HashMap<>();
        roomMap.put("id", room.getId());
        roomMap.put("hid", room.getHid());
        roomMap.put("info", room.getInfo());
        roomMap.put("title", room.getTitle());
        roomMap.put("number", room.getNumber());
        roomMap.put("prices", new ArrayList<>());

        Map<String, Object> myparams = new HashMap<>();
        myparams.put("myroom", roomMap);

        /**
         * 构建一个查询修改对象，查询出对象再对这些对象进行修改
         */
        UpdateQuery updateQuery = UpdateQuery.builder(room.getHid() + "")
                .withScript("ctx._source.rooms.add(params.myroom)")
                .withParams(myparams)
                .build();

        UpdateResponse resp = restTemplate.update(updateQuery, IndexCoordinates.of("hotal_index"));

        return resp.getResult() == UpdateResponse.Result.UPDATED;
    }

    /**
     * 同步保存酒店客房的价格信息
     * @param hid
     * @param roomPrices
     * @return
     */
    @Override
    public int insertRoomPirce(Integer hid, List<RoomPrice> roomPrices) {

        //批量修改集合
        List<UpdateQuery> updateQueryList = new ArrayList<>();

        //循环所有的价格信息
        roomPrices.stream().forEach(roomPrice -> {

            Map<String, Object> roomPriceMap = new HashMap<>();
            roomPriceMap.put("id", roomPrice.getId());
            roomPriceMap.put("rid", roomPrice.getRid());
            roomPriceMap.put("date", roomPrice.getDate().getTime());
            roomPriceMap.put("price", roomPrice.getPrice());
            roomPriceMap.put("number", roomPrice.getNumber());//共有多少房间
            roomPriceMap.put("hasNumber", roomPrice.getHasNumber());//剩余多少房间

            Map<String, Object> myparams = new HashMap<>();
            myparams.put("rid", roomPrice.getRid());
            myparams.put("myprice", roomPriceMap);

            //某一天的房间价格
            UpdateQuery updateQuery = UpdateQuery
                    .builder(hid + "")
                    .withScript("for(r in ctx._source.rooms){ if(r.id == params.rid) { r.prices.add(params.myprice) } }")
                    .withParams(myparams)
                    .build();

            updateQueryList.add(updateQuery);

        });


        restTemplate.bulkUpdate(updateQueryList, IndexCoordinates.of("hotal_index"));

        return 1;
    }

    /**
     * 修改对应酒店客房的价格信息
     * @param hid
     * @param roomPrice
     * @return
     */
    @Override
    public int updateRoomPrice(Integer hid, RoomPrice roomPrice) {

        Map<String, Object> params = new HashMap<>();
        params.put("rid", roomPrice.getRid());
        params.put("rpid", roomPrice.getId());
        params.put("price", roomPrice.getPrice());

        UpdateQuery updateQuery = UpdateQuery.builder(hid + "")
                .withScript("for(r in ctx._source.rooms){ if(r.id == params.rid){ for(rp in r.prices) { if(rp.id == params.rpid) { rp.price = params.price } } } }")
                .withParams(params)
                .build();

        restTemplate.update(updateQuery, IndexCoordinates.of("hotal_index"));
        return 1;
    }

    /**
     * 搜索酒店列表
     *
     * keyword?????
     * - hotalName, hotalName.pinyin
     *   hotalInfo, hotalInfo.pinyin
     *   keyword, keyword.pinyin
     *   brand, brand.pinyin
     *   address, address.pinyin
     *   reg, reg.pinyin
     *   room.title
     *
     * 城市？？？ - 优先搜索当前城市的酒店
     * 位置？？？ - 计算每个酒店距离我的位置   距离排序
     *
     * doc -> 酒店
     *          -> 客房1
     *             -> 2020-09-23 100 10 4
     *             -> 2020-09-24 150 10 10
     *             -> 2020-09-25 150 10 6
     *             ..
     *          -> 客房2
     *             -> 2020-09-23 100 10 4
     *             -> 2020-09-24 150 10 6
     *             ..
     *
     * 入店时间 离店时间？？？
     * 2020-09-23 - 2020-09-25
     *
     * 最小价格 最大价格？？？
     * 50 - 120
     *
     * @param searchParams
     * @return
     */
    @Override
    public List<Hotal> searchHotalList(SearchParams searchParams) {
        return null;
    }

    /**
     * 修改酒店对应的点击率
     * @param hid
     * @param num
     * @return
     */
    @Override
    public int updateHotalDjl(Integer hid, Integer num) {

        Map<String, Object> params = new HashMap<>();
        params.put("num", num);

        UpdateQuery updateQuery = UpdateQuery.builder(hid + "")
                .withScript("ctx._source.djl+=params.num")
                .withParams(params)
                .build();

        UpdateResponse response = restTemplate.update(updateQuery, IndexCoordinates.of("hotal_index"));
        return 1;
    }

    /**
     * 修改指定的房价预订数量
     * @param pricesParams
     * @return
     */
    @Override
    public int updateRoomNumber(PricesParams pricesParams) {

        String painless = "for(room in ctx._source.rooms) {" +
                "if(room.id == params.rid){" +
                "for(roomprice in room.prices){" +
                "if(roomprice.date >= params.beginTime && roomprice.date < params.endTime){" +
                "roomprice.number += params.rnumber" +
                "}" +
                "}" +
                "}" +
                "}";

        Map<String, Object> params = new HashMap<>();
        params.put("rid", pricesParams.getRid());
        params.put("beginTime", pricesParams.getBeginTime().getTime());
        params.put("endTime", pricesParams.getEndTime().getTime());
        params.put("rnumber", pricesParams.getRnumber());

        UpdateQuery updateQuery = UpdateQuery.builder(pricesParams.getHid() + "")
                .withScript(painless)
                .withParams(params)
                .build();

        restTemplate.update(updateQuery, IndexCoordinates.of("hotal_index"));
        return 1;
    }
}
